<?php
/**
 * Created by IntelliJ IDEA.
 * User: ahwwl
 * Date: 18-1-9
 * Time: 上午10:17
 */
namespace app\common;
use think\Cache;
use think\Log;
use WxPayApi;
use WxPayCloseOrder;
use WxPayConfig;
use WxPayException;
use WxPayJsApiPay;
use WxPayOrderQuery;
use WxPayRefund;
use WxPayResults;
use WxPayTransfers;
use WxPayUnifiedOrder;

include_once APP_PATH."common/WxpayAPI_php_v3/lib/WxPay.Api.php";
class weixin
{
    function GetWeiXinOpenid($baseUrl)
    {
        //通过code获得openid
        if (empty($_REQUEST["code"])){
            //触发微信返回code码

            $url = $this->__CreateOauthUrlForCode($baseUrl);
            Header("Location: $url");
            exit();
        } else {
            //获取code码，以获取openid
            $code = $_REQUEST["code"];
            $openid = $this->getOpenidFromMp($code);

            return $openid;
        }
    }

    /**
     * 获取OPENID url
     * @param $baseUrl
     * @return string
     */
    function __CreateOauthUrlForCode($baseUrl)
    {
        $urlObj["appid"] = WxPayConfig::APPID;
        $urlObj["redirect_uri"] = $baseUrl;
        $urlObj["response_type"] = "code";
        $urlObj["scope"] = "snsapi_base";
        $urlObj["state"] = "STATE"."#wechat_redirect";
        $bizString = $this->ToUrlParams($urlObj);
        return "https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString;
    }
    function getSignPackage($tokenType=1)
    {
        switch ($tokenType)
        {
            case 2:
                $appid = WxPayConfig::MPAPPID1;
                $apppsecret = WxPayConfig::MPAPPSECRET1;
                break;
            default:
                $appid = WxPayConfig::APPID;
                $apppsecret = WxPayConfig::APPSECRET;
                break;
        }
        $access_token = $this->getAccessToken($tokenType);
        $jssdk = new jssdk($appid,$apppsecret);
        $jssdk->access_token = $access_token;
        return $jssdk->getSignPackage();
    }

    /**
     * 根据code获取openid
     * @param $code
     * @param int $open_type
     * @return mixed
     */
    function getOpenidFromMp($code,$open_type=0)
    {
        switch ($open_type)
        {
            case 2:
                $url = 'https://api.weixin.qq.com/sns/jscode2session?appid='.WxPayConfig::MPAPPID1.'&secret='.WxPayConfig::MPAPPSECRET1.'&grant_type=authorization_code&js_code='.$code;
                break;
            default:
                $url = $this->__CreateOauthUrlForOpenid($code);
                break;
        }


        //初始化curl
        $ch = curl_init();
        //设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, 60);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,FALSE);
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        if(WxPayConfig::CURL_PROXY_HOST != "0.0.0.0"
            && WxPayConfig::CURL_PROXY_PORT != 0){
            curl_setopt($ch,CURLOPT_PROXY, WxPayConfig::CURL_PROXY_HOST);
            curl_setopt($ch,CURLOPT_PROXYPORT, WxPayConfig::CURL_PROXY_PORT);
        }
        //运行curl，结果以jason形式返回
        $res = curl_exec($ch);
        curl_close($ch);
        //取出openid
        $data = json_decode($res,true);
        $openid = "";
        if(!empty($data['openid']))
        {
            $openid = $data['openid'];
        }else{
            Log::error("getOpenidFromMp code:".$code.",open_type:".$open_type);
            Log::error($res);
        }

        return $openid;
    }

    /**
     * 根据code获取openid url
     * @param $code
     * @return string
     */
    function __CreateOauthUrlForOpenid($code)
    {
        $urlObj["appid"] = WxPayConfig::APPID;
        $urlObj["secret"] = WxPayConfig::APPSECRET;
        $urlObj["code"] = $code;
        $urlObj["grant_type"] = "authorization_code";
        $bizString = $this->ToUrlParams($urlObj);
        return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
    }
    function getAccessToken($tokenType=0)
    {
        $cache_key = "weixin_token_".$tokenType;
        $access_token = Cache::get($cache_key);
        if(empty($access_token))
        {
            switch ($tokenType)
            {
                case 2:
                    $appid = WxPayConfig::MPAPPID1;
                    $apppsecret = WxPayConfig::MPAPPSECRET1;
                    break;
                default:
                    $appid = WxPayConfig::APPID;
                    $apppsecret = WxPayConfig::APPSECRET;
                    break;
            }

            $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$appid."&secret=".$apppsecret;
            $response = $this->curl_url($url);
            if(!empty($response)&&$response["code"] == 200)
            {
                $data = json_decode($response["body"],true);
                $access_token = $data["access_token"];
                $expires_in = intval($data["expires_in"]);
                Cache::set($cache_key,$access_token,$expires_in);
            }
        }

        return $access_token;
    }
    function getwxacodeunlimit($data,$tokenType)
    {
        $cache_key = "weixin_token_".$tokenType;
        $token = $this->getAccessToken($tokenType);
        $url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=".$token;
        $response = $this->curl_url($url,[],json_encode($data));
        if(!empty($response["body"]))
        {
            if(substr($response["body"],0,1) == "{")
            {
                Cache::rm($cache_key);
                return $this->getwxacodeunlimit($data,$tokenType);
            }
            return $response["body"];
        }
        return false;
    }
    function sendMPTemplate($open_id,$template_id,$page,$form_id,$data=[])
    {
        $cache_key = "weixin_token_2";
        $access_token = $this->getAccessToken(2);
        $url = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=".$access_token;
        $parem = [
            "touser"=> $open_id,
            "template_id"=> $template_id,
            "form_id"=> $form_id,
            "data"=> $data
        ];
        if(!empty($page))
        {
            $parem["page"] = $page;
        }
        $response = curl_url($url,[],json_encode($parem));
        if(!empty($response)&&$response["code"] == 200)
        {
            $data = json_decode($response["body"],true);
            $errcode = $data["errcode"];
            if(empty($errcode))
            {
                return true;
            }elseif($errcode == 40001)
            {
                Cache::rm($cache_key);
                return $this->sendMPTemplate($open_id,$template_id,$page,$form_id,$data);
            }

        }
        return false;

    }
    function sendText($open_id,$content)
    {
        $info = [
            "touser"=>$open_id,
            "msgtype"=>"text",
            "text"=>[
                "content"=>$content
            ]
        ];
        $access_token = $this->getAccessToken();
        $url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=".$access_token;
        $response = curl_url($url,[],json_encode($info));
        if(!empty($response)&&$response["code"] == 200)
        {
            $data = json_decode($response["body"],true);
            $errcode = $data["errcode"];
            if(empty($errcode))
            {
                return true;
            }
        }
        return false;

    }
    function CloseOrder($order_no,$open_type)
    {
        $input = new WxPayCloseOrder();
        $input->SetOut_trade_no($order_no);
        switch ($open_type)
        {
            case 2:
                $input->SetAppid(WxPayConfig::MPAPPID1);
                break;
            default:
                $input->SetAppid(WxPayConfig::APPID);
                break;
        }
        try {
            $order = WxPayApi::closeOrder($input);
            if($order["return_code"] == "FAIL")
            {
                throw new WxPayException($order["return_msg"],500);
            }
            if($order["result_code"] == "FAIL")
            {
                throw new WxPayException($order["err_code_des"],500);
            }
            return true;
        } catch (WxPayException $e) {

        }
        return false;

    }
    /**
     * 统一下单
     * @param $openId
     * @param $order_no
     * @param $money
     * @param $body
     * @param $notify_url
     * @param int $open_type
     * @return array
     * @throws WxPayException
     */
    function GetWeiXinUnifiedOrder($openId,$order_no,$money,$body,$notify_url,$open_type=0)
    {


//②、统一下单
        $input = new WxPayUnifiedOrder();
        $input->SetBody($body);
//    $input->SetAttach("test");

        $input->SetOut_trade_no($order_no);
        $input->SetTotal_fee($money);
        $input->SetTime_start(date("YmdHis",time()+8*3600));
        $input->SetTime_expire(date("YmdHis", time() + 8*3600+600));
//    $input->SetGoods_tag("test");
        $input->SetProduct_id("500001");
        $input->SetNotify_url($notify_url);
        $input->SetTrade_type("JSAPI");
        $input->SetOpenid($openId);
        switch ($open_type)
        {
            case 2:
                $input->SetAppid(WxPayConfig::MPAPPID1);
                break;
            default:
                $input->SetAppid(WxPayConfig::APPID);
                break;
        }

        $order = WxPayApi::unifiedOrder($input);
        if($order["return_code"] == "FAIL")
        {
            throw new WxPayException($order["return_msg"],500);
        }
        if($order["result_code"] == "FAIL")
        {
            throw new WxPayException($order["err_code_des"],500);
        }
        $jsApiParameters = $this->GetJsApiParameters($order);
        return $jsApiParameters;
    }

    /**
     * 统一下单
     * @param $order_no
     * @param $money
     * @param $body
     * @param $notify_url
     * @param $wap_url
     * @param $wap_name
     * @return \成功时返回，其他抛异常
     * @throws WxPayException
     */
    function GetWeiXinH5UnifiedOrder($order_no,$money,$body,$notify_url,$wap_url,$wap_name)
    {


//②、统一下单
        $input = new WxPayUnifiedOrder();
        $input->SetBody($body);
//    $input->SetAttach("test");
        $input->SetAppid(WxPayConfig::APPID);
        $input->SetOut_trade_no($order_no);
        $input->SetTotal_fee($money);
        $input->SetTime_start(date("YmdHis",time()+8*3600));
        $input->SetTime_expire(date("YmdHis", time() + 8*3600+600));
//    $input->SetGoods_tag("test");
        $input->SetGoods_tag("充值");
        $input->SetProduct_id("500001");
        $input->SetNotify_url($notify_url);
        $input->SetTrade_type("MWEB");
        $Scene_info = [
            "h5_info"=>[
                "type"=>"Wap",
                "wap_url"=>$wap_url,
                "wap_name"=>$wap_name
            ]
        ];
        $input->SetScene_info(json_encode($Scene_info));

        $order = WxPayApi::unifiedOrder($input);
        if($order["return_code"] == "FAIL")
        {
            throw new WxPayException($order["return_msg"],500);
        }
        return $order;
    }

    function GetWeiXinNATIVEUnifiedOrder($order_no,$money,$body,$notify_url)
    {


//②、统一下单
        $input = new WxPayUnifiedOrder();
        $input->SetBody($body);
//    $input->SetAttach("test");
        $input->SetAppid(WxPayConfig::APPID);
        $input->SetOut_trade_no($order_no);
        $input->SetTotal_fee($money);
        $input->SetTime_start(date("YmdHis",time()+8*3600));
        $input->SetTime_expire(date("YmdHis", time() + 8*3600+600));
        $input->SetGoods_tag("充值");
        $input->SetProduct_id("500001");
        $input->SetNotify_url($notify_url);
        $input->SetTrade_type("NATIVE");


        $order = WxPayApi::unifiedOrder($input);
        if($order["return_code"] == "FAIL")
        {
            throw new WxPayException($order["return_msg"],500);
        }
        return $order;
    }

    /**
     * 获取下单JSAPI str
     * @param $UnifiedOrderResult
     * @return array
     * @throws WxPayException
     */
    function GetJsApiParameters($UnifiedOrderResult)
    {
        if(!array_key_exists("appid", $UnifiedOrderResult)
            || !array_key_exists("prepay_id", $UnifiedOrderResult)
            || $UnifiedOrderResult['prepay_id'] == "")
        {
            throw new WxPayException("参数错误");
        }
        $jsapi = new WxPayJsApiPay();
        $jsapi->SetAppid($UnifiedOrderResult["appid"]);
        $timeStamp = time();
        $jsapi->SetTimeStamp("$timeStamp");
        $jsapi->SetNonceStr(WxPayApi::getNonceStr());
        $jsapi->SetPackage("prepay_id=" . $UnifiedOrderResult['prepay_id']);
        $jsapi->SetSignType("MD5");
        $jsapi->SetPaySign($jsapi->MakeSign());
        $parameters = $jsapi->GetValues();
        $parameters["prepay_id"] = $UnifiedOrderResult['prepay_id'];
        return $parameters;
    }

    /**根据订单号查询验证
     * @param $order_no
     * @param int $type
     * @return array|bool|Object|\成功时返回，其他抛异常
     * @throws WxPayException
     */
    function QueryOrder($order_no,$type=0)
    {
        $input = new WxPayOrderQuery();
        if($type == 0)
        {
            $input->SetOut_trade_no($order_no);
        }else{
            $input->SetTransaction_id($order_no);
        }
        $result = WxPayApi::orderQuery($input);
        if(!is_array($result))
            return false;

        if(!array_key_exists("return_code", $result))
            return false;
        if(!array_key_exists("result_code", $result))
            return false;
        if(!array_key_exists("cash_fee", $result))
            return false;

        return $result;
    }
    function PayResult($response)
    {
        $result = [];
        try {
            $result = WxPayResults::Init($response);
        } catch (WxPayException $e) {

        }
        return $result;

    }

    /**
     * 退款
     * @param $out_trade_no
     * @param $total_fee
     * @param $refund_fee
     * @param string $desc
     * @return bool
     * @throws WxPayException
     */
    function RefundOrder($out_trade_no,$total_fee,$refund_fee,$desc="")
    {
        $input = new WxPayRefund();
        $input->SetOut_trade_no($out_trade_no);
        $input->SetTotal_fee($total_fee);
        $input->SetRefund_fee($refund_fee);
        $input->SetOut_refund_no($out_trade_no."-".date("YmdHis"));
        $input->SetOp_user_id(WxPayConfig::MCHID);
        if(!empty($desc))
            $input->SetRefund_desc($desc);
        $result = WxPayApi::refund($input);
        if(!empty($result["return_code"]) && $result["result_code"] &&$result["return_code"] == "SUCCESS" &&$result["result_code"] == "SUCCESS")
        {
            return true;
        }
        return false;
    }
    function ToUrlParams($urlObj)
    {
        $buff = "";
        foreach ($urlObj as $k => $v)
        {
            if($k != "sign"){
                $buff .= $k . "=" . $v . "&";
            }
        }

        $buff = trim($buff, "&");
        return $buff;
    }
    function mmpaymkttransfers($trade_no,$openId,$money,$desc,$ip,$open_type = 0)
    {
        try
        {
            $input = new WxPayTransfers();
            $input->SetTradeNo($trade_no);
            $input->SetOpenId($openId);
            $input->SetCheckName("NO_CHECK");
            $input->SetAmount($money);
            $input->SetDesc($desc);
            $input->SetSpbillCreateIp($ip);
            switch ($open_type)
            {
                case 2:
                    $input->SetAppid(WxPayConfig::MPAPPID1);
                    break;
                default:
                    $input->SetAppid(WxPayConfig::APPID);
                    break;
            }

            $result = WxPayApi::transfers($input);
            if(!empty($result["return_code"]) && $result["result_code"] &&$result["return_code"] == "SUCCESS" &&$result["result_code"] == "SUCCESS")
            {
                return [
                    "error"=>0,
                    "partner_trade_no"=>$result["partner_trade_no"],
                    "payment_no"=>$result["payment_no"],
                    "payment_time"=>$result["payment_time"]];
            }else{
                if(!empty($result["err_code_des"]))
                    return ["error"=>1,"msg"=>$result["err_code_des"]];
            }
        }catch (\Exception $e)
        {
        }

        return false;

    }

    function curl_url($url,$headers=[],$body="")
    {
        $result = ["code"=>500,"body"=>"","error_info"=>""];
        try{
            $ch = curl_init();
            //设置选项，包括URL
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            if(!empty($headers))
                curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
            if($body)
            {
                curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
            }

            //执行并获取HTML文档内容
            $output = curl_exec($ch);
            if($output === false){
                $result["error_info"]= curl_errno($ch);
            }
            $result["code"] = curl_getinfo($ch,CURLINFO_HTTP_CODE);
            $result["body"] = $output;
            //释放curl句柄
            curl_close($ch);
        }catch (\Exception $e)
        {
            $result["error_info"] = $e->getMessage();
        }
        return $result;
    }
}
